/**
  ******************************************************************************
  * @file    mt006_can.c
  * @author  MIC Software Team
  * @version V1.0.0
  * @date    09/01/2020
  * @brief   This file provides all the CAN firmware functions.
  ******************************************************************************  
  * @attention
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, MIC SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * <h2><center>&copy; COPYRIGHT MIC</center></h2>
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "mt006_can.h"
#include "mt006_rcc.h"

/** @addtogroup MT006_StdPeriph_Driver
  * @{
  */

/** @defgroup CAN 
  * @brief CAN driver modules
  * @{
  */ 

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/** @defgroup CAN_Private_Functions
  * @{
  */

/**
  * @brief  Deinitializes the CAN peripheral registers to their default reset values.
  * @param  None
  * @retval None
  */
void CAN_DeInit(void)
{ 
	/* Enable CAN reset state */
	RCC_APBPeriphResetCmd(RCC_PRESETCTRL_CAN, ENABLE);	
	/* Release CAN from reset state */
	RCC_APBPeriphResetCmd(RCC_PRESETCTRL_CAN,  DISABLE);	
}

/**
  * @brief  Initializes the CAN peripheral according to the specified
  *   parameters in the CAN_InitStruct.
  * @param  CAN_InitStruct: pointer to a CAN_InitTypeDef structure that
  *   contains the configuration information for the CAN peripheral.
  * @retval Constant indicates initialization succeed which will be 
  *   CANINITFAILED or CANINITOK.
  */
uint8_t CAN_Init(CAN_InitTypeDef* CAN_InitStruct)
{
	uint8_t InitStatus = CANINITFAILED;

	/* exit from sleep mode */
	CAN->MOD &= (~(uint8_t)CAN_MOD_SM);

	/* Into Reset mode */
	CAN->MOD |= CAN_MOD_RM ;

	/* Set the bit timing register */

	CAN->BTR0 = CAN_InitStruct->CAN_BTR0;
	CAN->BTR1 = CAN_InitStruct->CAN_BTR1;
	CAN->BTR2 = CAN_InitStruct->CAN_BTR2;

	CAN->OCR = CAN_InitStruct->CAN_OCR;

	/* Into normal mode */
	CAN->MOD &= (~(uint8_t)CAN_MOD_RM) ;

	InitStatus = CANINITOK ;

	/* At this step, return the status of initialization */
	return InitStatus;
}

/**
  * @brief  Initializes the CAN peripheral according to the specified
  *   parameters in the CAN_FilterInitStruct.
  * @param  CAN_FilterInitStruct: pointer to a CAN_FilterInitTypeDef
  *   structure that contains the configuration information.
  * @retval None.
  */
void CAN_FilterInit(CAN_FilterInitTypeDef* CAN_FilterInitStruct)
{
	 __IO uint8_t *ACR;
	 __IO uint8_t *AMR;

	assert_param(IS_CAN_ALL_FILTERMASK(CAN_FilterInitStruct->CAN_FilterMaskId1));
	assert_param(IS_CAN_ALL_FILTERMASK(CAN_FilterInitStruct->CAN_FilterMaskId3));
	assert_param(IS_CAN_FILTER_MODE(CAN_FilterInitStruct->CAN_FilterMode));
	  /* Into Reset mode */
  	CAN->MOD |= CAN_MOD_RM ;

	if(CAN_FilterInitStruct->CAN_FilterMode == 1)
	{
		CAN->MOD |= (((uint8_t)CAN_FilterInitStruct->CAN_FilterMode)<<3) ;

	}
	 else
	{
	  	CAN->MOD &= (~(((uint8_t)CAN_FilterInitStruct->CAN_FilterMode)<<3)) ;
	}
    
	ACR = (uint8_t *)&(CAN->sRTx);
	AMR = ACR+4 ;
	
	ACR[0] = CAN_FilterInitStruct->CAN_FilterId0;
	ACR[1] = CAN_FilterInitStruct->CAN_FilterId1;
	ACR[2] = CAN_FilterInitStruct->CAN_FilterId2;
	ACR[3] = CAN_FilterInitStruct->CAN_FilterId3;
	
	AMR[0] = CAN_FilterInitStruct->CAN_FilterMaskId0;
	AMR[1] = CAN_FilterInitStruct->CAN_FilterMaskId1;
	AMR[2] = CAN_FilterInitStruct->CAN_FilterMaskId2;
	AMR[3] = CAN_FilterInitStruct->CAN_FilterMaskId3;
	 /* Into normal mode */
  	CAN->MOD &= (~(uint8_t)CAN_MOD_RM) ;
}

/**
  * @brief  Fills each CAN_InitStruct member with its default value.
  * @param  CAN_InitStruct: pointer to a CAN_InitTypeDef structure which
  *   will be initialized.
  * @retval None.
  */
void CAN_StructInit(CAN_InitTypeDef* CAN_InitStruct)
{
  
}



/**
  * @brief  Enables or disables the specified CAN interrupts.
  * @param  CAN_IT: specifies the CAN interrupt sources to be enabled or disabled.
  *   This parameter can be: 
  *        -CAN_IT_RIE, 
  *        -CAN_IT_TIE, 
  *        -CAN_IT_EIE,
  *        -CAN_IT_DOIE, 
  *        -CAN_IT_WUIE, 
  *        -CAN_IT_EPIE,
  *        -CAN_IT_ALIE or 
  *        -CAN_IT_BEIE. 
  * @param  NewState: new state of the CAN interrupts.
  *   This parameter can be: ENABLE or DISABLE.
  * @retval None.
  */
void CAN_ITConfig(uint32_t CAN_IT, FunctionalState NewState)
{
	assert_param(IS_FUNCTIONAL_STATE(NewState));

	if (NewState != DISABLE)
	{
		/* Enable the selected CAN interrupt */
		CAN->IER |= CAN_IT;
	}
	else
	{
		/* Disable the selected CAN interrupt */
		CAN->IER &= ~CAN_IT;
	}
}

/**
  * @brief  Initiates the transmission of a message.
  * @param  TxMessage: pointer to a structure which contains CAN Id, CAN
  *   DLC and CAN datas.
  * @retval The number of the mailbox that is used for transmission
  *   or CAN_NO_MB if there is no empty mailbox.
  */
uint8_t CAN_Transmit(CanTxMsg* TxMessage)
{
	 assert_param(IS_CAN_IDTYPE(TxMessage->FF));
  	 assert_param(IS_CAN_RTR(TxMessage->RTR));
 	 assert_param(IS_CAN_DLC(TxMessage->DLC));
  
    ((CAN_TxArea_SFF_TypeDef *)&(CAN->sRTx))->Control = (TxMessage->DLC&0x0F)| 
						((TxMessage->RTR&0x01)<<6)|
						((TxMessage->FF&0x01)<<7);

	if(TxMessage->FF == CAN_ID_STD)
	{
		((CAN_TxArea_SFF_TypeDef *)&(CAN->sRTx))->ID[0] = (uint8_t) (((TxMessage->StdId << 5)&0x0000FF00)>>8);
		((CAN_TxArea_SFF_TypeDef *)&(CAN->sRTx))->ID[1] = (uint8_t) (((TxMessage->StdId << 5)&0x000000FF)>>0);
	
	
		((CAN_TxArea_SFF_TypeDef *)&(CAN->sRTx))->DATA[7] = TxMessage->Data[7];
	    ((CAN_TxArea_SFF_TypeDef *)&(CAN->sRTx))->DATA[6] = TxMessage->Data[6];
	    ((CAN_TxArea_SFF_TypeDef *)&(CAN->sRTx))->DATA[5] = TxMessage->Data[5];
	    ((CAN_TxArea_SFF_TypeDef *)&(CAN->sRTx))->DATA[4] = TxMessage->Data[4];
		((CAN_TxArea_SFF_TypeDef *)&(CAN->sRTx))->DATA[3] = TxMessage->Data[3];
	    ((CAN_TxArea_SFF_TypeDef *)&(CAN->sRTx))->DATA[2] = TxMessage->Data[2];
	    ((CAN_TxArea_SFF_TypeDef *)&(CAN->sRTx))->DATA[1] = TxMessage->Data[1]; 
	    ((CAN_TxArea_SFF_TypeDef *)&(CAN->sRTx))->DATA[0] = TxMessage->Data[0];
	 }
	 else
	 {
	 	((CAN_TxArea_EFF_TypeDef *)&(CAN->sRTx))->ID[0] = (uint8_t) (((TxMessage->ExtId<<3)&0xff000000)>>24);
		((CAN_TxArea_EFF_TypeDef *)&(CAN->sRTx))->ID[1] = (uint8_t) (((TxMessage->ExtId<<3)&0x00ff0000)>>16);
		((CAN_TxArea_EFF_TypeDef *)&(CAN->sRTx))->ID[2] = (uint8_t) (((TxMessage->ExtId<<3)&0x0000ff00)>>8);
		((CAN_TxArea_EFF_TypeDef *)&(CAN->sRTx))->ID[3] = (uint8_t) (((TxMessage->ExtId<<3)&0x000000ff));
	
		((CAN_TxArea_EFF_TypeDef *)&(CAN->sRTx))->DATA[7] = TxMessage->Data[7];
	    ((CAN_TxArea_EFF_TypeDef *)&(CAN->sRTx))->DATA[6] = TxMessage->Data[6];
	    ((CAN_TxArea_EFF_TypeDef *)&(CAN->sRTx))->DATA[5] = TxMessage->Data[5];
	    ((CAN_TxArea_EFF_TypeDef *)&(CAN->sRTx))->DATA[4] = TxMessage->Data[4];
		((CAN_TxArea_EFF_TypeDef *)&(CAN->sRTx))->DATA[3] = TxMessage->Data[3];
	    ((CAN_TxArea_EFF_TypeDef *)&(CAN->sRTx))->DATA[2] = TxMessage->Data[2];
	    ((CAN_TxArea_EFF_TypeDef *)&(CAN->sRTx))->DATA[1] = TxMessage->Data[1]; 
	    ((CAN_TxArea_EFF_TypeDef *)&(CAN->sRTx))->DATA[0] = TxMessage->Data[0];
	 }
    /* Request transmission */
    CAN->CMR |=((uint8_t)CAN_CMR_TR);
  
  return 1;
}

/**
  * @brief  Receives a message.
  * @param  RxMessage: pointer to a structure receive message which 
  *   contains CAN Id, CAN DLC, CAN datas and FMI number.
  * @retval None.
  */
void CAN_Receive(CanRxMsg* RxMessage)
{
	uint32_t i=0;
	uint32_t ID[4];

	/* Get the Id */
	RxMessage->FF = ((uint8_t)(0x80 & ((CAN_RxArea_SFF_TypeDef *)&(CAN->sRTx))->Control)) >> 7;
	if (RxMessage->FF == CAN_ID_STD)
	{
		ID[0] = ((CAN_RxArea_SFF_TypeDef *)&(CAN->sRTx))->ID[0];
		ID[1] = (((CAN_RxArea_SFF_TypeDef *)&(CAN->sRTx)))->ID[1];
		RxMessage->StdId = ((ID[0]<<8) | ID[1]) >> 5;
		for(i=0;i<8;i++)
		{
			/* Get the data field */
			RxMessage->Data[i] = (uint8_t)((CAN_RxArea_SFF_TypeDef *)&(CAN->sRTx))->DATA[i];
		}
	}
	else
	{
		ID[0] =((*(CAN_RxArea_EFF_TypeDef *)(&(CAN->sRTx))).ID[0]);
		ID[1] =((*(CAN_RxArea_EFF_TypeDef *)(&(CAN->sRTx))).ID[1]);
		ID[2] =((*(CAN_RxArea_EFF_TypeDef *)(&(CAN->sRTx))).ID[2]);
		ID[3] =((*(CAN_RxArea_EFF_TypeDef *)(&(CAN->sRTx))).ID[3]);

		RxMessage->ExtId = ((ID[0]<<24) | (ID[1]<<16) | (ID[2]<<8) | ID[3]) >> 3;
		for(i=0;i<8;i++)
		{
			/* Get the data field */
			RxMessage->Data[i] = (uint8_t)((*(CAN_RxArea_EFF_TypeDef *)(&(CAN->sRTx))).DATA[i]);
		}
	}

	RxMessage->RTR = ((uint8_t)(0x40 & ((CAN_RxArea_SFF_TypeDef *)&(CAN->sRTx))->Control)) >> 6;
	/* Get the DLC */
	RxMessage->DLC = ((uint8_t)(0x0F & ((CAN_RxArea_SFF_TypeDef *)&(CAN->sRTx))->Control));

	CAN->CMR |= ((uint8_t)CAN_CMR_RRB);
}

/**
  * @}
  */

/**
  * @}
  */

/**
  * @}
  */

/******************* (C) COPYRIGHT MIC *****END OF FILE****/
